package com.rmfyzxfw.caseprocess.util;

import com.google.common.collect.Lists;
import com.rmfyzxfw.caseprocess.model.dto.RuleItemDTO;

import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.List;
import java.util.Random;

/**
 * @description:
 * @Author: GYW  742926306@qq.com
 * @Date: 2024/8/23 14:39
 */
public class RuleExpressionUtil {
    private static final ScriptEngine engine;
    private static final ScriptEngine engine2;

    static {
        ScriptEngineManager manager = new ScriptEngineManager();
        engine = manager.getEngineByName("groovy");
        engine2 = manager.getEngineByName("nashorn");

        // 预热
        try {
            engine.eval("true && false");
//            engine2.eval("true && false");
        } catch (ScriptException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 计算表达式
     * groovy  第一次 1393
     * 10000次总耗时  1732
     *
     * @param expression
     * @param ruleItemDTOS
     * @return
     */
    public static boolean evalGroovy(String expression, List<RuleItemDTO> ruleItemDTOS) throws ScriptException {
        Bindings bindings = engine.createBindings();

        for (RuleItemDTO ruleItemDTO : ruleItemDTOS) {
            bindings.put(ruleItemDTO.getItem(), ruleItemDTO.isResult());
        }

        return (boolean) engine.eval(expression, bindings);
    }

    /**
     * 计算表达式
     *
     * @param expression
     * @return
     */
    public static boolean evalGroovy(String expression) throws ScriptException {
        return (boolean) engine.eval(expression);
    }

    /**
     * js  第一次 112
     * 10000次总耗时  4178
     *
     * @param expression
     * @param ruleItemDTOS
     */
    public static boolean evalJS(String expression, List<RuleItemDTO> ruleItemDTOS) throws ScriptException {
        Bindings bindings = engine2.createBindings();

        for (RuleItemDTO ruleItemDTO : ruleItemDTOS) {
            bindings.put(ruleItemDTO.getItem(), ruleItemDTO.isResult());
        }

        Object eval = engine2.eval(expression, bindings);
        return Boolean.parseBoolean(String.valueOf(eval));
    }

    public static void main(String[] args) throws ScriptException {
        String e = "(a9oUnc9KQ380d)";
        List<RuleItemDTO> ruleItemDTOS = Lists.newArrayList();
        ruleItemDTOS.add(new RuleItemDTO("a9oUnc9KQ380d", true));
        System.out.println(evalGroovy(e, ruleItemDTOS));
    }

    private static void compareJSAndGroovy() throws ScriptException {
        System.out.println("groovy");
        String expression = "(A1 && A11) || (C && D) || E";
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            if (i == 0) {
                long startFirst = System.currentTimeMillis();
                evalGroovy(expression, buildRuleItems(Lists.newArrayList()));
                System.out.println("第一次 " + (System.currentTimeMillis() - startFirst));
            } else {
                evalGroovy(expression, buildRuleItems(Lists.newArrayList()));
            }
        }
        System.out.println("总耗时");
        System.out.println(System.currentTimeMillis() - start);

        System.out.println("js");
        String expression2 = "(A1 && A11) || (C && D) || E";
        long start2 = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            if (i == 0) {
                long startFirst2 = System.currentTimeMillis();
                evalJS(expression2, buildRuleItems(Lists.newArrayList()));
                System.out.println("第一次 " + (System.currentTimeMillis() - startFirst2));
            } else {
                evalJS(expression2, buildRuleItems(Lists.newArrayList()));
            }
        }
        System.out.println("总耗时");
        System.out.println(System.currentTimeMillis() - start2);
    }

    public static List<RuleItemDTO> buildRuleItems(List<RuleItemDTO> ruleItemDTOS) {
        ruleItemDTOS.add(new RuleItemDTO("A1", getRandomBooleanValue()));
        ruleItemDTOS.add(new RuleItemDTO("A11", getRandomBooleanValue()));
        ruleItemDTOS.add(new RuleItemDTO("C", getRandomBooleanValue()));
        ruleItemDTOS.add(new RuleItemDTO("D", getRandomBooleanValue()));
        ruleItemDTOS.add(new RuleItemDTO("E", getRandomBooleanValue()));
        return ruleItemDTOS;
    }

    public static Boolean getRandomBooleanValue() {
        Random r = new Random();
        int i = r.nextInt(2);
//        return i == 0 ? "false" : "true";
        return i == 0;
    }
}